4.2: Menus

Contents:

Types of menus

A menu is a set of options the user can select from to perform a function, such as searching for information, saving information, editing information, or navigating to a screen. Android offers the following types of menus, which are useful for different situations (refer to the figure below): Types of Menus

  1. Options menu: Appears in the app bar and provides the primary options that affect using the app itself. Examples of menu options: Search to perform a search, Bookmark to save a link to a screen, and Settings to navigate to the Settings screen.
  2. Context menu: Appears as a floating list of choices when the user performs a long tap on an element on the screen. Examples of menu options: Edit to edit the element, Delete to delete it, and Share to share it over social media.
  3. Contextual action bar: Appears at the top of the screen overlaying the app bar, with action items that affect the selected element(s). Examples of menu options: Edit, Share, and Delete for one or more selected elements.
  4. Popup menu: Appears anchored to a view such as an ImageButton, and provides an overflow of actions or the second part of a two-part command. Example of a popup menu: the Gmail app anchors a popup menu to the app bar for the message view with Reply, Reply All, and Forward.

The app bar and options menu

The app bar (also called the action bar) is a dedicated space at the top of each activity screen. When you create an activity from a template (such as Empty Template), an app bar is automatically included for the activity in a CoordinatorLayout root view group at the top of the view hierarchy.

The app bar by default shows the app title, or the name defined in AndroidManifest.xml by the android:label attribute for the activity. It may also include the Up button for navigating up to the parent activity, which is described in the next chapter.

The options menu in the app bar provides navigation to other activities in the app, or the primary options that affect using the app itself — but not ones that perform an action on an element on the screen. For example, your options menu might provide the user choices for navigating to other activities, such as placing an order, or for actions that have a global impact on the app, such as changing settings or profile information.

The options menu appears in the right corner of the app bar. The app bar is split into four different functional areas that apply to most apps: The App Bar

  1. Navigation button or Up button: Use a navigation button in this space to open a navigation drawer, or use an Up button for navigating up through your app's screen hierarchy to the parent activity. Both are described in the next chapter.
  2. Title: The title in the app bar is the app title, or the name defined in AndroidManifest.xml by the android:label attribute for the activity.
  3. Action icons for the options menu: Each action icon appears in the app bar and represents one of the options menu's most frequently used items. Less frequently used options menu items appear in the overflow options menu.
  4. Overflow options menu: The overflow icon opens a popup with option menu items that are not shown as icons in the app bar.

Frequently-used options menu items should appear as icons in the app bar. The overflow options menu shows the rest of the menu: Arrangement of Options for the Options Menu

In the above figure:

  1. App bar. The app bar includes the app title, the options menu, and the overflow button.
  2. Options menu action icons. The first two options menu items appear as icons in the app bar.
  3. Overflow button. The overflow button (three vertical dots) opens a menu that shows more options menu items.
  4. Options overflow menu. After clicking the overflow button, more options menu items appear in the overflow menu.

Adding the app bar

Each activity that uses the default theme also has an ActionBar as its app bar. Some themes also set up an ActionBar as an app bar by default. When you start an app from a template such as Empty Activity, an ActionBar appears as the app bar.

However, as features were added to the native ActionBar over various Android releases, the native ActionBar behaves differently depending on the version of Android running on the device. For this reason, if you are adding an options menu, you should use the v7 appcompat support library's Toolbar as an app bar. Using the Toolbar makes it easy to set up an app bar that works on the widest range of devices, and also gives you room to customize your app bar later on as your app develops. Toolbar includes the most recent features, and works for any device that can use the support library.

In order to use Toolbar as the app bar (rather than the default ActionBar) for an activity, do one of the following:

  • Start your project with the Basic Activity template, which implements the Toolbar for the activity as well as a rudimentary options menu (with one item, Settings). You can skip this section.
  • Do it yourself, as shown in this section:
    1. Add the support libraries: appcompat and design.
    2. Use a NoActionBar theme and styles for the app bar and background.
    3. Add an AppBarLayout and a Toolbar to the layout.
    4. Add code to the activity to set up the app bar.

Adding the support libraries

If you start an app project using the Basic Activity template, the template adds the following support libraries for you, so you can skip this step.

If you are not using the Basic Activity template, add the appcompat support library (current version is v7) for the Toolbar class, and the design library for the NoActionBar themes, to your project:

  1. Choose Tools > Android > SDK Manager to check that the Android Support Repository is installed; if it is not, install it.
  2. Open the build.gradle file for your app, and add the support library feature project identifiers to the dependencies section. For example, to include support:appcompat and support:design, add:
    compile 'com.android.support:appcompat-v7:23.4.0'
    compile 'com.android.support:design:23.4.0'
    
    Note: Update the version numbers for dependencies if necessary. If the version number you specified is lower than the currently available library version number, Android Studio will warn you ("a newer version of com.android.support:design is available"). Update the version number to the one Android Studio tells you to use.

Using themes to design the app bar

If you start an app project using the Basic Activity template, the template adds the theme to replace the ActionBar with a Toolbar, so you can skip this step.

If you are not using the Basic Activity template, you can use the Toolbar class for the app bar by turning off the default ActionBar using a NoActionBar theme for the activity. Themes in Android are similar to styles, except that they are applied to an entire app or activity rather than to a specific view.

When you create a new project in Android Studio, an app theme is automatically generated for you. For example, if you start an app project with the Empty Activity or Basic Activity template, the AppTheme theme is provided in styles.xml in the res > values directory.

Tip: You learn more about themes in the chapter on drawables, styles and themes.

You can modify the theme to provide a style for the app bar and app background so that the app bar is visible and stands out against the background. Follow these steps:

  1. Open the styles.xml file. You should already have the following in the file:

    <resources>
       <!-- Base application theme. -->
       <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
          <!-- Customize your theme here. -->
          <item name="colorPrimary">@color/colorPrimary</item>
          <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
          <item name="colorAccent">@color/colorAccent</item>
       </style>
       ...
    </resources>
    

    AppTheme "inherits"—takes on all the styles—from a parent them called Theme.AppCompat.Light.DarkActionBar, which is a standard theme supplied with Android. However, you can override an inherited style with another style by adding the other style to styles.xml.

  2. Add the AppTheme.NoActionBar, AppTheme.AppBarOverlay, and AppTheme.PopupOverlay styles under the AppTheme style, as shown below. These styles will override the style attributes with the same names in AppTheme, affecting the appearance of the app bar and the app's background:

    <resources>
       <!-- Base application theme. -->
       <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
          ...
       </style>
    
       <style name="AppTheme.NoActionBar">
          <item name="windowActionBar">false</item>
          <item name="windowNoTitle">true</item>
       </style>
    
       <style name="AppTheme.AppBarOverlay"
                parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
    
       <style name="AppTheme.PopupOverlay"
                parent="ThemeOverlay.AppCompat.Light" />
       ...
    </resources>
    
  3. In the AndroidManifest.xml file, add the NoActionBar theme in appcompat to the <application> element. Using this theme prevents the app from using the native ActionBar class to provide the app bar:
    <activity
       ...
       android:theme="@style/AppTheme.NoActionBar">
    </activity>
    

Adding AppBarLayout and a Toolbar to the layout

If you start an app project using the Basic Activity template, the template adds the AppBarLayout and Toolbar for you, so you can skip this step.

If you are not using the Basic Activity template, you can include the Toolbar in an activity's layout by adding an AppBarLayout and a Toolbar element. AppBarLayout is a vertical LinearLayout which implements many of the features of the material designs app bar concept, such as scrolling gestures. Keep in mind the following:

  • AppBarLayout must be a direct child within a CoordinatorLayout root view group, and Toolbar must be a direct child within AppBarLayout, as shown below:
    <android.support.design.widget.CoordinatorLayout
       ... >
       <android.support.design.widget.AppBarLayout
          ...>
          <android.support.v7.widget.Toolbar
                ...
                />
       </android.support.design.widget.AppBarLayout>
       ...
    </android.support.design.widget.CoordinatorLayout>
    
  • Position the Toolbar at the top of the activity's layout, since you are using it as an app bar.
  • AppBarLayout also requires a separate content layout sibling for the content that scrolls underneath the app bar. You can add this sibling as a view group (such as RelativeLayout or LinearLayout) as follows:
    • In the same layout file for the activity (as in activity_main.xml)
    • In a separate layout file, such as content_main.xml, which you can then add to the activity's layout file with an include statement:
      <include layout="@layout/content_main" />
      
  • You need to set the content sibling's scrolling behavior, as shown below with the RelativeLayout group, to be an instance of AppBarLayout.ScrollingViewBehavior:

    <RelativeLayout
       ...
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       app:layout_behavior="@string/appbar_scrolling_view_behavior"
       ... >
    
    </RelativeLayout>
    

    The layout behavior for the RelativeLayout is set to the string resource @string/appbar_scrolling_view_behavior, which controls the scrolling behavior of the screen in relation to the app bar at the top. This string resource represents the following string, which is defined in the values.xml file that should not be edited:

    android.support.design.widget.AppBarLayout$ScrollingViewBehavior
    

    This behavior is defined by the AppBarLayout.ScrollingViewBehavior class. This behavior should be used by Views which can scroll vertically—it supports nested scrolling to automatically scroll any AppBarLayout siblings.

Adding code to set up the app bar

If you start an app project using the Basic Activity template, the template adds the code needed to set up the app bar, so you can skip this step.

If you are not using the Basic Activity template, you can follow these steps to set up the app bar in the activity:

  1. Make sure that any activity that you want to show an app bar extends AppCompatActivity:
    public class MyActivity extends AppCompatActivity {
    ...
    }
    
  2. In the activity's onCreate() method, call the activity's setSupportActionBar() method, and pass the activity's toolbar (assuming the Toolbar element's id is toolbar). The setSupportActionBar() method sets the toolbar as the app bar for the activity:
    @Override
    protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);
       Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
       setSupportActionBar(toolbar);
    }
    

The activity now shows the app bar. By default, the app bar contains just the name of the app.

Adding the options menu

Android provides a standard XML format to define options menu items. Instead of building the menu in your activity's code, you can define the menu and all its items in an XML menu resource. A menu resource defines an application menu (options menu, context menu, or popup menu) that can be inflated with MenuInflater, which loads the resource as a Menu object in your activity or fragment.

If you start an app project using the Basic Activity template, the template adds the menu resource for you and inflates the options menu with MenuInflater, so you can skip this step and go right to "Defining how menu items appear".

If you are not using the Basic Activity template, use the resource-inflate design pattern, which makes it easy to create an options menu. Follow these steps (refer to the figure below): Design Pattern for Options Menu

  1. XML menu resource. Create an XML menu resource file for the menu items, and assign appearance and position attributes as described in the next section.
  2. Inflating the menu. Override the onCreateOptionsMenu() method in your activity or fragment to inflate the menu.
  3. Handling menu item clicks. Menu items are views, so you can use the android:onClick attribute for each menu item. However, the onOptionsItemSelected() method can handle all the menu item clicks in one place, and determine which menu item was clicked, which makes your code easier to understand.
  4. Performing actions. Create a method to perform an action for each options menu item.

Creating an XML resource for the menu

Follow these steps to add the menu items to an XML menu resource:

  1. Click the res directory, and choose File > New > Android resource directory, choose menu in the Resource type drop-down menu, and click OK.
  2. Click the new menu directory, and choose File > New > Menu resource file, enter the name of the file as menu_main or something similar, and click OK. The new menu_main.xml file now resides within the menu directory.
  3. Open the menu_main.xml file (if not already open), and click the Text tab next to the Design tab at the bottom of the pane to show the text of the file.
  4. Add the first options menu item using the <item … /> tag. In this example, the item is Settings:

    <menu xmlns:android="http://schemas.android.com/apk/res/android"
       ...>
       <item
          android:id="@+id/action_settings"
          android:title="@string/settings" />
    </menu>
    

    After setting up and inflating the XML resource in the activity or fragment code, the overflow icon in the app bar, when clicked, would show the options menu with just one option (Settings): App Bar with Options Menu

Defining how menu items appear

If you start an app project using the Basic Activity template, the template adds the options menu with one option: Settings.

To add more options menu items, add more <item … /> tags in the menu_main.xml file. For example, in the following snippet, two options menu items are defined: @string/settings (Settings) and @string/action_order (Order):

<menu xmlns:android="http://schemas.android.com/apk/res/android"
   ...>
   <item
      android:id="@+id/action_settings"
      android:title="@string/settings" />
   <item
      android:id="@+id/action_order"
      android:icon="@drawable/ic_order_white"
      android:title="@string/action_order"/>
</menu>

Within each <item … /> tag you can add the attributes to define how the menu item appears, such as the order of its appearance relative to the other items, and whether the item can appear as an icon in the app bar. Any item you set to not appear in the app bar (or that can't fit in the app bar given the display orientation) is placed in order in the overflow menu).

Whenever possible, you want to show the most frequently used actions using icons in the app bar so that the user can click them without having to first click the overflow button.

Adding icons for menu items

To specify icons for actions, you need to first add the icons as image assets to the drawable folder by following these steps (see Image Asset Studio for a complete description):

  1. Expand res in the Project view, and right-click (or Command-click) drawable.
  2. Choose New > Image Asset. The Configure Image Asset dialog appears.
  3. Choose Action Bar and Tab Items in the drop-down menu.
  4. Edit the name of the icon (for example, ic_order_white for the Order menu item).
  5. Click the clipart image (the Android logo) to select a clipart image as the icon. A page of icons appears. Click the icon you want to use.
  6. (Optional) Choose HOLO_DARK from the Theme drop-down menu. This sets the icon to be white against a dark-colored (or black) background. Click Next.
  7. Click Finish in the Confirm Icon Path dialog.

Icon and appearance attributes

Use the following attributes to govern the menu item's appearance:

  • android:icon: An image to use as the menu item icon. For example, the following menu item defines ic_order_white as its icon:
    <item
        android:id="@+id/action_order"
        android:icon="@drawable/ic_order_white"
        android:title="@string/action_order"/>
    
  • android:title: A string for the title of the menu item.
  • android:titleCondensed: A string to use as a condensed title for situations in which the normal title is too long.

Position attributes

Use the android:orderInCategory attribute to specify the order in which the menu items appear in the menu, with the lowest number appearing higher in the menu. This is usually the order of importance of the item within the menu. For example, if you want Order to be first, followed by Status, Favorites, and Contact, the following table shows the priority of these items in the menu:

Menu Item

orderInCategory attribute

Order

10

Status

20

Favorites

40

Contact

100

Position of Options Menu Items Defined by orderInCategory Attribute

Note: While the numbers 1, 2, 3, and 4 would also work in the above example, the numbers 10, 20, 40, and 100 leave room for additional menu items to be added later between them.

Use the app:showAsAction attribute to show menu items as icons in the app bar, with the following values:

  • "always": Always place this item in the app bar. Use this only if it's critical that the item appear in the app bar (such as a Search icon). If you set multiple items to always appear in the app bar, they might overlap something else in the app bar, such as the app title.
  • "ifRoom": Only place this item in the app bar if there is room for it. If there is not enough room for all the items marked "ifRoom", the items with the lowest orderInCategory values are displayed in the app bar, and the remaining items are displayed in the overflow menu.
  • "never": Never place this item in the app bar. Instead, list the item in the app bar's overflow menu.
  • "withText": Also include the title text (defined by android:title) with the item. The title text appears anyway if the item appears in the overflow menu, so this attribute is used primarily to include the title with the icon in the app bar.

For example, the following menu item's icon appears in the app bar only if there is room for it:

<item
   android:id="@+id/action_favorites"
   android:icon="@drawable/ic_favorites_white"
   android:orderInCategory="40"
   android:title="@string/action_favorites"
   app:showAsAction="ifRoom" />

Icons in the App Bar and Overflow Menu in Vertical Orientation on a Smartphone

In the above figure:

  1. Options menu action icons. The first two options menu items appear as action icons in the app bar: Order (the shopping cart icon) and Info (the "i" icon).
  2. Overflow button. Clicking the overflow button shows the overflow menu.
  3. Options overflow menu. The overflow menu shows more of the options menu: Favorites and Contact. Favorites (the heart icon) doesn't fit into the app bar in vertical orientation, but may appear in horizontal orientation on a smartphone, or in both orientations on a tablet, as shown below. Icons in the App Bar and Overflow Menu in Vertical (left) and Horizontal (right) orientations.

Inflating the menu resource

If you start an app project using the Basic Activity template, the template adds the code for inflating the options menu with MenuInflater, so you can skip this step.

If you are not using the Basic Activity template, inflate the menu resource in your activity by using the onCreateOptionsMenu() method (with the Override annotation) with the getMenuInflater() method of the Activity class.

The getMenuInflater() method returns a MenuInflater, which is a class used to instantiate menu XML files into Menu objects. The MenuInflater class provides the inflate() method, which takes as a parameter the resource id for an XML layout resource to load (R.menu.menu_main in the following example), and the Menu to inflate into (menu in the following example):

@Override
public boolean onCreateOptionsMenu(Menu menu) {
   getMenuInflater().inflate(R.menu.menu_main, menu);
   return true;
}

Handling the menu item click

As with a button, the android:onClick attribute defines a method to call when this menu item is clicked. You must declare the method in the activity as public and accept a MenuItem as its only parameter, which indicates the item clicked.

For example, you could define the Favorites item in the menu resource file to use the android:onClick attribute to call the onFavoritesClick() method:

<item
        android:id="@+id/action_favorites"
        android:icon="@drawable/ic_favorites_white"
        android:orderInCategory="40"
        android:title="@string/action_favorites"
        app:showAsAction="ifRoom"
        android:onClick="onFavoritesClick" />

You would declare the onFavoritesClick() method in the activity:

public void onFavoritesClick(MenuItem item) {
    // The item parameter indicates which item was clicked.
    // Add code to handle the Favorites click.
}

However, the onOptionsItemSelected() method of the Activities class can handle all the menu item clicks in one place, and determine which menu item was clicked, which makes your code easier to understand. The Basic Activity template provides an implementation of the onOptionsItemSelected() method with a switch case block to call the appropriate method (such as showOrder) based on the menu item's id, which you can retrieve using the getItemId() method of the Adapter class:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
   switch (item.getItemId()) {
      case R.id.action_order:
         showOrder();
         return true;
      case R.id.action_status:
         showStatus();
         return true;
      case R.id.action_contact:
         showContact();
         return true;
      default:
         // Do nothing
   }
   return super.onOptionsItemSelected(item);
}

Contextual menu

Use a contextual menu to allow users to take an action on a selected view. You can provide a context menu for any View, but they are most often used for items in a RecyclerView, GridView, or other view collections in which the user can perform direct actions on each item.

Android provides two kinds of contextual menus:

  • A context menu, shown on the left side in the figure below, appears as a floating list of menu items when the user performs a long tap on a view element on the screen. It is typically used to modify the view element or use it in some fashion. For example, a context menu might include Edit to edit a view element, Delete to delete it, and Share to share it over social media. Users can perform a contextual action on one view element at a time.
  • A Contextual action bar, shown on the right side of the figure below, appears at the top of the screen in place of the app bar or underneath the app bar, with action items that affect the selected view element(s). Users can perform an action on multiple view elements at once (if your app allows it). Floating Context Menu (left) and Contextual Action Bar (right)

Floating context menu

The familiar resource-inflate design pattern is used to create a floating context menu, modified to include registering (associating) the context menu with a view: Design Pattern for Context Menu

Follow these steps to create a floating context menu for one or more view elements (refer to figure above):

  1. Create an XML menu resource file for the menu items, and assign appearance and position attributes (as described in the previous section).
  2. Register a view to the context menu using the registerForContextMenu() method of the Activity class.
  3. Implement the onCreateContextMenu() method in your activity or fragment to inflate the menu.
  4. Implement the onContextItemSelected() method in your activity or fragment to handle menu item clicks.
  5. Create a method to perform an action for each context menu item.

Creating the XML resource file

Create the XML menu resource directory and file by following the steps in the previous section. Use a suitable name for the file, such as menu_context. Add the context menu items (in this example, the menu items are Edit, Share, and Delete):

<item
   android:id="@+id/context_edit"
   android:title="@string/edit"
   android:orderInCategory="10"/>

<item
   android:id="@+id/context_share"
   android:title="@string/share"
   android:orderInCategory="20"/>

<item
   android:id="@+id/context_delete"
   android:title="@string/delete"
   android:orderInCategory="30"/>

Registering a view to the context menu

Register a view to the context menu by calling the registerForContextMenu() method and passing it the view. Registering a context menu for a view sets the View.OnCreateContextMenuListener on the view to this activity, so that onCreateContextMenu() will be called when it is time to show the context menu. (You implement onCreateContextMenu in the next section.)

For example, in the onCreate() method for the activity, add the registerForContextMenu() statement:

...
// Registering the context menu to the text view of the article.
TextView article_text = (TextView) findViewById(R.id.article);
registerForContextMenu(article_text);
...

Multiple views can be registered to the same context menu. If you want each item in a ListView or GridView to provide the same context menu, register all items for a context menu by passing the ListView or GridView to registerForContextMenu().

Implementing the onCreateContextMenu() method

When the registered view receives a long-click event, the system calls the onCreateContextMenu() method, which you can override in your activity or fragment. This is where you define the menu items, usually by inflating a menu resource.

For example:

@Override
public void onCreateContextMenu(ContextMenu menu, View v,
                         ContextMenu.ContextMenuInfo menuInfo) {
   super.onCreateContextMenu(menu, v, menuInfo);
   MenuInflater inflater = getMenuInflater();
   inflater.inflate(R.menu.menu_context, menu);
}

In the above code:

  • The menu parameter for onCreateContextMenu() is the context menu to be built.
  • The v parameter is the view registered for the context menu.
  • The menuInfo parameter is extra information about the view registered for the context menu. This information varies depending on the class of v, which could be a RecyclerView or a GridView. If you are registering a RecyclerView or GridView, you would instantiate a ContextMenu.ContextMenuInfo object to provide the information about the item selected, and pass it as menuInfo, such as the row id, position, or child view.

The MenuInflater class provides the inflate() method, which takes as a parameter the resource id for an XML layout resource to load (menu_context in the above example), and the Menu to inflate into (menu in the above example).

Implementing the onContextItemSelected() method

When the user clicks on a menu item, the system calls the onContextItemSelected() method. You override this method in your activity or fragment in order to determine which menu item was clicked, and for which view the menu is appearing. You also use it to implement the appropriate action for the menu items, such as editNote() and shareNote() below for the Edit and Share menu items. For example:

@Override
public boolean onContextItemSelected(MenuItem item) {
   switch (item.getItemId()) {
      case R.id.context_edit:
         editNote();
         return true;
      case R.id.context_share:
         shareNote();
         return true;
      default:
         return super.onContextItemSelected(item);
   }
}

The above example uses the getItemId() method to get the id for the selected menu item, and uses it in a switch case block to determine which action to take. The id is the android:id attribute assigned to the menu item in the XML menu resource file.

When the user performs a long-click on the article in the text view, the floating context menu appears and the user can click a menu item. User Long-clicks the Text to Show the Context Menu

If you are using the menuInfo information for a RecyclerView or GridView, you would add a statement before the switch case block to gathers the specific information about the selected view (for info) by using AdapterView.AdapterContextMenuInfo:

AdapterView.AdapterContextMenuInfo info =
            (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();

Contextual action bar

A contextual action bar appears at the top of the screen to present actions the user can perform on a view after long-clicking the view, as shown in the figure below. Contextual Action Bar and View

In the above figure:

  1. Contextual action bar. The bar offers three actions on the right side (Edit, Share, and Delete) and the Done button (left arrow icon) on the left side.
  2. View. View on which a long-click triggers the contextual action bar.

The contextual action bar appears only when contextual action mode, a system implementation of ActionMode, occurs as a result of the user performing a long-click on the View.

ActionMode represents a user interface (UI) mode for providing alternative interaction, replacing parts of the normal UI until finished. For example, text selection is implemented as an ActionMode, as are contextual actions that work on a selected item on the screen. Selecting a section of text or long-clicking a view triggers ActionMode.

While this mode is enabled, the user can select multiple items (if your app allows it), deselect items, and continue to navigate within the activity. The action mode is disabled and the contextual action bar disappears when the user deselects all items, presses the Back button, or taps Done (left-arrow icon) on the left side of the bar.

Follow these steps to create a contextual action bar (refer to the figure below):

  1. Create an XML menu resource file for the menu items, and assign an icon to each one (as described in a previous section).
  2. Set the long-click listener to the view that should trigger the contextual action bar using the setOnLongClickListener() method. Call startActionMode() within the setOnLongClickListener() method when the user performs a long tap on the view.
  3. Implement the ActionMode.Callback interface to handle the ActionMode lifecycle. Include in this interface the action for responding to a menu item click in the onActionItemClicked() callback method.
  4. Create a method to perform an action for each context menu item. Design Pattern for Contextual Action Bar

Creating the XML resource file

Create the XML menu resource directory and file by following the steps in a previous section. Use a suitable name for the file, such as menu_context. Add icons for the context menu items (in this example, the menu items are Edit, Share, and Delete). For example, the Edit menu item would have these attributes:

<item
   android:id="@+id/context_edit"
   android:orderInCategory="10"
   android:icon="@drawable/ic_action_edit_white"
   android:title="@string/edit" />

The standard contextual action bar has a dark background. Use a light or white color for the icons. If you are using clip art icons, choose HOLO_DARK for the Theme drop-down menu when creating the new image asset.

Setting the long-click listener

Use setOnLongClickListener() to set a long-click listener to the View that should trigger the contextual action bar. Add the code to set the long-click listener to the activity class (such as MainActivity) using the activity's onCreate() method. Follow these steps:

  1. Declare the member variable mActionMode in the class definition for the activity:

    private ActionMode mActionMode;
    

    You will call startActionMode() to enable ActionMode, which returns the ActionMode created. By saving this in a member variable (mActionMode), you can make changes to the contextual action bar in response to other events.

  2. Set up the contextual action bar listener in the onCreate() method, using View as the type for the view in order to use the setOnLongClickListener:
    @Override
    protected void onCreate(Bundle savedInstanceState) {
       ...
       View articleView = findViewById(article);
       articleView.setOnLongClickListener(new View.OnLongClickListener() {
          ...
          // Add method here to start ActionMode after long-click.
          ...
       });
    }
    

Implementing the ActionMode.Callback interface

Before you can add the code to onCreate() to start ActionMode, you must implement the ActionMode.Callback interface to manage the action mode lifecycle. In its callback methods, you can specify the actions for the contextual action bar, and respond to clicks on action items.

  1. Add the following method to the activity class (such as MainActivity) to implement the interface:
    public ActionMode.Callback mActionModeCallback = new
                                         ActionMode.Callback() {
       ...
       // Add code to create action mode here.
       ...
    }
    
  2. Add the onCreateActionMode() code within the brackets of the above method to create action mode (the full code is provided at the end of this section):

    @Override
    public boolean onCreateActionMode(ActionMode mode, Menu menu) {
      // Inflate a menu resource providing context menu items
      MenuInflater inflater = mode.getMenuInflater();
      inflater.inflate(R.menu.menu_context, menu);
      return true;
    }
    

    The onCreateActionMode() method inflates the menu using the same pattern used for a floating context menu. But this inflation occurs only when ActionMode is created, which is when the user performs a long-click. The MenuInflater class provides the inflate() method, which takes as a parameter the resource id for an XML layout resource to load (menu_context in the above example), and the Menu to inflate into (menu in the above example).

  3. Add the onActionItemClicked() method with your handlers for each menu item:

    @Override
    public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
    switch (item.getItemId()) {
      case R.id.context_edit:
         editNote();
         mode.finish();
         return true;
      case R.id.context_share:
         shareNote();
         mode.finish();
         return true;
      default:
         return false;
    }
    

    The above code above uses the getItemId() method to get the id for the selected menu item, and uses it in a switch case block to determine which action to take. The id in each case statement is the android:id attribute assigned to the menu item in the XML menu resource file.

    The actions shown are the editNote() and shareNote() methods, which you can create in the same activity. After the action is picked, you use the mode.finish() method to close the contextual action bar.

  4. Add the onPrepareActionMode() and onDestroyActionMode() methods, which manage the ActionMode lifecycle:

    @Override
    public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
          return false; // Return false if nothing is done.
    }
    

    The onPrepareActionMode() method shown above is called each time ActionMode occurs, and is always called after onCreateActionMode().

    @Override
    public void onDestroyActionMode(ActionMode mode) {
          mActionMode = null;
    }
    

    The onDestroyActionMode() method shown above is called when the user exits ActionMode by clicking Done in the contextual action bar, or clicking on a different view.

  5. Review the full code for the ActionMode.Callback interface implementation:

    public ActionMode.Callback mActionModeCallback = new
                                            ActionMode.Callback() {
       @Override
       public boolean onCreateActionMode(ActionMode mode, Menu menu) {
          // Inflate a menu resource providing context menu items
          MenuInflater inflater = mode.getMenuInflater();
          inflater.inflate(R.menu.menu_context, menu);
          return true;
       }
    
       // Called each time ActionMode is shown. Always called after
       // onCreateActionMode.
       @Override
       public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
          return false; // Return false if nothing is done
       }
    
       // Called when the user selects a contextual menu item
       @Override
       public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
          switch (item.getItemId()) {
             case R.id.context_edit:
                editNote();
                mode.finish();
                return true;
             case R.id.context_share:
                shareNote();
                mode.finish();
                return true;
             default:
                return false;
          }
       }
    
       // Called when the user exits the action mode
       @Override
       public void onDestroyActionMode(ActionMode mode) {
          mActionMode = null;
       }
    };
    

Starting ActionMode

You use startActionMode() to start ActionMode after the user performs a long-click.

  1. To start ActionMode, add the onLongClick() method within the brackets of the setOnLongClickListener method in onCreate():

    @Override
    protected void onCreate(Bundle savedInstanceState) {
       ...
       articleView.setOnLongClickListener(new View.OnLongClickListener() {
          // Called when the user long-clicks on articleView
          public boolean onLongClick(View view) {
             if (mActionMode != null) return false;
             // Start the contextual action bar
             // using the ActionMode.Callback.
             mActionMode =
                   MainActivity.this.startActionMode(mActionModeCallback);
             view.setSelected(true);
             return true;
          }
       });
    }
    

    The above code first ensures that the ActionMode instance is not recreated if it's already active by checking whether mActionMode is null before starting the action mode:

    if (mActionMode != null) return false;
    

    When the user performs a long-click, the call is made to startActionMode() using the ActionMode.Callback interface, and the contextual action bar appears at the top of the display. The setSelected() method changes the state of this view to selected (set to true).

  2. Review the code for the onCreate() method in the activity, which now includes setOnLongClickListener() and startActionMode():

    @Override
    protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);
    
       // set up the contextual action bar listener
       View articleView = findViewById(article);
       articleView.setOnLongClickListener(new View.OnLongClickListener() {
          // Called when the user long-clicks on articleView
          public boolean onLongClick(View view) {
             if (mActionMode != null) return false;
             // Start the contextual action bar
             // using the ActionMode.Callback.
             mActionMode =
                    MainActivity.this.startActionMode(mActionModeCallback);
             view.setSelected(true);
             return true;
          }
       });
    }
    

A PopupMenu is a vertical list of items anchored to a View. It appears below the anchor view if there is room, or above the view otherwise.

A popup menu is typically used to provide an overflow of actions (similar to the overflow action icon for the options menu) or the second part of a two-part command. Use a popup menu for extended actions that relate to regions of content in your activity. Unlike a context menu, a popup menu is anchored to a Button (View), is always available, and it's actions generally do not affect the content of the View.

For example, the Gmail app uses a popup menu anchored to the overflow icon in the app bar when showing an email message. The popup menu items Reply, Reply All, and Forward are related to the email message, but don't affect or act on the message. Actions in a popup menu should not directly affect the corresponding content (use a contextual menu to directly affect selected content). As shown below, a popup can be anchored to the overflow action button in the action bar. Popup Menu Anchored to the Overflow Action Button

Creating a pop-up menu

Follow these steps to create a popup menu (refer to figure below): Design Pattern for a Popup Menu

  1. Create an XML menu resource file for the popup menu items, and assign appearance and position attributes (as described in a previous section).
  2. Add an ImageButton for the popup menu icon in the XML activity layout file.
  3. Assign onClickListener() to the button.
  4. Override the onClick() method to inflate the popup menu and register it with PopupMenu.OnMenuItemClickListener.
  5. Implement the onMenuItemClick() method.
  6. Create a method to perform an action for each popup menu item.

Creating the XML resource file

Create the XML menu resource directory and file by following the steps in a previous section. Use a suitable name for the file, such as menu_popup.

Adding an ImageButton for the icon to click

Use an ImageButton in the activity layout for the icon that triggers the popup menu. Popup menus are anchored to a view in the activity, such as an ImageButton. The user clicks it to see the menu.

<ImageButton
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/button_popup"
    android:src="@drawable/@drawable/ic_action_popup"/>

Assigning onClickListener to the button

  1. Create a member variable (mButton) in the activity's class definition:
    public class MainActivity extends AppCompatActivity {
       private ImageButton mButton;
       ...
    }
    
  2. In the onCreate() method for the same activity, assign the ImageButton in the layout to the member variable, and assign onClickListener() to the button:
    @Override
    protected void onCreate(Bundle savedInstanceState) {
       ...
       mButton = (ImageButton) findViewById(R.id.button_popup);
       mButton.setOnClickListener(new View.OnClickListener() {
       ...
       // define onClick here
       ...
    });
    

Inflating the popup menu

As part of the setOnClickListener() method within onCreate(), add the onClick() method to inflate the popup menu and register it with PopupMenu.OnMenuItemClickListener:

@Override
public void onClick(View v) {
   //Creating the instance of PopupMenu
   PopupMenu popup = new PopupMenu(MainActivity.this, mButton);
   //Inflating the Popup using xml file
   popup.getMenuInflater().inflate(R.menu.menu_popup, popup.getMenu());
   //registering popup with OnMenuItemClickListener
   popup.setOnMenuItemClickListener(new
                              PopupMenu.OnMenuItemClickListener() {
      ...
      // Add onMenuItemClick here
      ...
            // Perform action here
      ...
}

After instantiating a PopupMenu object (popup in the above example), the method uses the MenuInflater class and its inflate() method, which takes as parameters:

  • The resource id for an XML layout resource to load (menu_popup in the example above)
  • The Menu to inflate into (popup.getMenu() in the example above).

The code then registers the popup with the listener, PopupMenu.OnMenuItemClickListener.

Implementing onMenuItemClick

To perform an action when the user selects a popup menu item, implement the onMenuItemClick() callback within the above setOnClickListener() method, and finish the method with popup.show to show the popup menu:

         public boolean onMenuItemClick(MenuItem item) {
            // Perform action here
            return true;
         }
      });
      popup.show();  //show the popup menu
   }
});// close the setOnClickListener method

Putting these pieces together, the entire onCreate() method should now look like this:

private ImageButton mButton;

@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_main);
   ...
   // popup button setup
   mButton = (ImageButton) findViewById(R.id.button_popup);
   mButton.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
         //Creating the instance of PopupMenu
         PopupMenu popup = new PopupMenu(MainActivity.this, mButton);
         //Inflating the Popup using xml file
         popup.getMenuInflater().inflate(R.menu.menu_popup, popup.getMenu());

         //registering popup with OnMenuItemClickListener
         popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
            public boolean onMenuItemClick(MenuItem item) {
               // Perform action here
               return true;
            }
         });
         popup.show();//show the popup menu
      }
   });//close the setOnClickListener method
 }

Popup Menu Anchored to ImageButton

The related exercises and practical documentation is in Android Developer Fundamentals: Practicals.

Learn more

results matching ""

    No results matching ""